﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Admin.NET.Application.Entity;
using Admin.NET.Core.Service;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using SqlSugar;
using Yitter.IdGenerator;

namespace Admin.NET.Application;

/// <summary>
/// 来料检验服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class incomingService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<incoming> _incomingRep;
    private readonly ISqlSugarClient _sqlSugarClient;

    public incomingService(SqlSugarRepository<incoming> incomingRep, ISqlSugarClient sqlSugarClient)
    {
        _incomingRep = incomingRep;
        _sqlSugarClient = sqlSugarClient;
    }

    /// <summary>
    /// 分页查询来料检验 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询来料检验")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<incomingOutput>> Page(PageincomingInput input)
    {

        input.Keyword = input.Keyword?.Trim();
        var query = _incomingRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.batch.Contains(input.Keyword) || u.vendor.Contains(input.Keyword) || u.Order.Contains(input.Keyword) || u.results.Contains(input.Keyword) || u.Auditer.Contains(input.Keyword) || u.Auditremark.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.batch), u => u.batch.Contains(input.batch.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.vendor), u => u.vendor.Contains(input.vendor.Trim()))
           // .WhereIF(!string.IsNullOrWhiteSpace(input.Order), u => u.Order.Contains(input.Order.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.results), u => u.results.Contains(input.results.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Auditer), u => u.Auditer.Contains(input.Auditer.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Auditremark), u => u.Auditremark.Contains(input.Auditremark.Trim()))
            .WhereIF(input.material != null, u => u.material == input.material)
            .WhereIF(input.scheme != null, u => u.scheme == input.scheme)
            .WhereIF(input.batchnumber != null, u => u.batchnumber == input.batchnumber)
            .WhereIF(input.AudittimeRange?.Length == 2, u => u.Audittime >= input.AudittimeRange[0] && u.Audittime <= input.AudittimeRange[1])
            .LeftJoin<tentative>((u, material) => u.material == material.Id)
            .LeftJoin<inspectionscheme>((u, material, scheme) => u.scheme == scheme.Id)
            .Select((u, material, scheme) => new incomingOutput
            {
                Id = u.Id,
                material = u.material,
                materialFkDisplayName = $"{material.itemcode}",
                scheme = u.scheme,
                schemeFkDisplayName = $"{scheme.schemename}",
                batch = u.batch,
                vendor = u.vendor,
                batchnumber = u.batchnumber,
                Order = u.Order,
                status = u.status,
                results = u.results,
                Auditer = u.Auditer,
                Audittime = u.Audittime,
                Auditremark = u.Auditremark,
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
            });
		return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 获取来料检验详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取来料检验详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<incoming> Detail([FromQuery] QueryByIdincomingInput input)
    {
        return await _incomingRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 增加来料检验 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加来料检验")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddincomingInput input)
    {
        var entity = input.Adapt<incoming>();
        entity.Order=YitIdHelper.NextId().ToString();
        entity.results = "未检验";
        return await _incomingRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新来料检验 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新来料检验")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateincomingInput input)
    {
        var entity = input.Adapt<incoming>();
        await _incomingRep.AsUpdateable(entity)
        .IgnoreColumns(u => new {
            u.Order,
            u.status,
            u.results,
            u.Auditer,
            u.Audittime,
            u.Auditremark,
        })
        .ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除来料检验 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除来料检验")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteincomingInput input)
    {
        var entity = await _incomingRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _incomingRep.FakeDeleteAsync(entity);   //假删除
        //await _incomingRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 批量删除来料检验 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除来料检验")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteincomingInput> input)
    {
        var exp = Expressionable.Create<incoming>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _incomingRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _incomingRep.FakeDeleteAsync(list);   //假删除
        //return await _incomingRep.DeleteAsync(list);   //真删除
    }
    
    /// <summary>
    /// 获取下拉列表数据 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取下拉列表数据")]
    [ApiDescriptionSettings(Name = "DropdownData"), HttpPost]
    public async Task<Dictionary<string, dynamic>> DropdownData(DropdownDataincomingInput input)
    {
        var materialData = await _incomingRep.Context.Queryable<tentative>()
            .InnerJoinIF<incoming>(input.FromPage, (u, r) => u.Id == r.material)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.itemcode}"
            }).ToListAsync();
        var schemeData = await _incomingRep.Context.Queryable<inspectionscheme>()
            .InnerJoinIF<incoming>(input.FromPage, (u, r) => u.Id == r.scheme)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.schemename}"
            }).ToListAsync();
        return new Dictionary<string, dynamic>
        {
            { "material", materialData },
            { "scheme", schemeData },
        };
    }
    
    /// <summary>
    /// 导出来料检验记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出来料检验记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageincomingInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportincomingOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        return ExcelHelper.ExportTemplate(list, "来料检验导出记录");
    }
    
    /// <summary>
    /// 下载来料检验数据导入模板 ⬇️
    /// </summary>
    /// <returns></returns>
    [DisplayName("下载来料检验数据导入模板")]
    [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify]
    public IActionResult DownloadTemplate()
    {
        return ExcelHelper.ExportTemplate(new List<ExportincomingOutput>(), "来料检验导入模板", (_, info) =>
        {
            if (nameof(ExportincomingOutput.materialFkDisplayName) == info.Name) return _incomingRep.Context.Queryable<tentative>().Select(u => $"{u.itemcode}").Distinct().ToList();
            if (nameof(ExportincomingOutput.schemeFkDisplayName) == info.Name) return _incomingRep.Context.Queryable<inspectionscheme>().Select(u => $"{u.schemename}").Distinct().ToList();
            return null;
        });
    }
    
    /// <summary>
    /// 导入来料检验记录 💾
    /// </summary>
    /// <returns></returns>
    [DisplayName("导入来料检验记录")]
    [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
    public IActionResult ImportData([Required] IFormFile file)
    {
        lock (this)
        {
            var stream = ExcelHelper.ImportData<ImportincomingInput, incoming>(file, (list, markerErrorAction) =>
            {
                _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems =>
                {
                    // 链接 物料
                    var materialLabelList = pageItems.Where(x => x.materialFkDisplayName != null).Select(x => x.materialFkDisplayName).Distinct().ToList();
                    if (materialLabelList.Any()) {
                        var materialLinkMap = _incomingRep.Context.Queryable<tentative>().Where(u => materialLabelList.Contains($"{u.itemcode}")).ToList().ToDictionary(u => $"{u.itemcode}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.material = materialLinkMap.GetValueOrDefault(e.materialFkDisplayName ?? "");
                            if (e.material == null) e.Error = "物料链接失败";
                        });
                    }
                    // 链接 检验方案
                    var schemeLabelList = pageItems.Where(x => x.schemeFkDisplayName != null).Select(x => x.schemeFkDisplayName).Distinct().ToList();
                    if (schemeLabelList.Any()) {
                        var schemeLinkMap = _incomingRep.Context.Queryable<inspectionscheme>().Where(u => schemeLabelList.Contains($"{u.schemename}")).ToList().ToDictionary(u => $"{u.schemename}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.scheme = schemeLinkMap.GetValueOrDefault(e.schemeFkDisplayName ?? "");
                            if (e.scheme == null) e.Error = "检验方案链接失败";
                        });
                    }
                    
                    // 校验并过滤必填基本类型为null的字段
                    var rows = pageItems.Where(x => {
                        return true;
                    }).Adapt<List<incoming>>();
                    
                    var storageable = _incomingRep.Context.Storageable(rows)
                        .SplitError(it => it.Item.batch?.Length > 32, "批次号长度不能超过32个字符")
                        .SplitError(it => it.Item.vendor?.Length > 32, "供应商长度不能超过32个字符")
                        .SplitError(it => it.Item.Order?.Length > 32, "单号长度不能超过32个字符")
                        .SplitError(it => it.Item.results?.Length > 32, "结果长度不能超过32个字符")
                        .SplitError(it => it.Item.Auditer?.Length > 32, "审核人长度不能超过32个字符")
                        .SplitError(it => it.Item.Auditremark?.Length > 32, "审核备注长度不能超过32个字符")
                        .SplitInsert(_ => true)
                        .ToStorage();
                    
                    storageable.BulkCopy();
                    storageable.BulkUpdate();
                    
                    // 标记错误信息
                    markerErrorAction.Invoke(storageable, pageItems, rows);
                });
            });
            
            return stream;
        }
    }
}
